package ucd.csi.comp30220.fall2011.oteop.util;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.util.NoSuchElementException;

/**
 * Finds currently available server ports. <br>
 * Lifted wholesale from <code>org.apache.mina.util.AvailablePortFinder</code>
 * 
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
 * @see <a href="http://www.iana.org/assignments/port-numbers">IANA.org</a>
 * 
 */
public class PortFinder {

    /**
     * The minimum number of server port number.
     */
    public static final int MIN_PORT_NUMBER = 1025;

    /**
     * The maximum number of server port number.
     */
    public static final int MAX_PORT_NUMBER = 49151;

    static {
        new PortFinder();
    }

    private PortFinder() {
        System.setProperty("java.net.preferIPv4Stack", "true");
    }
    
    /**
     * Gets the next available port starting at the lowest port number.
     * 
     * @throws NoSuchElementException
     *             if there are no ports available
     */
    public static synchronized int getNextAvailable() {
        for (int i = MIN_PORT_NUMBER; i <= MAX_PORT_NUMBER; i++) {
            if (available(i)) {
                return i;
            }
        }
        throw new NoSuchElementException(
            "Could not find an available port!");
        
    }

    /**
     * Checks to see if a specific port is available.
     * 
     * @param port the port to check for availability
     */
    private static boolean available(int port) {
        ServerSocket ss = null;
        DatagramSocket ds = null;
        try {
            ss = new ServerSocket(port);
            ss.setReuseAddress(true);
            ds = new DatagramSocket(port);
            ds.setReuseAddress(true);
            return true;
        } catch (IOException e) {
            // Do nothing
        } finally {
            if (ds != null) {
                ds.close();
            }

            if (ss != null) {
                try {
                    ss.close();
                } catch (IOException e) {
                    // should not be thrown
                }
            }
        }
        return false;
    }
}
